
package org.femto.math.vis;

import org.femto.math.linalg.*;
import org.femto.math.Util;

import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;

import javax.media.opengl.GL;

public class ManipulatorManager {

    public enum MANIPULATOR {
        ORBIT,
        PAN,
        ZOOM,
        LOOK,
        FOV
    }

    class Trigger {
        public int modifier;
        public boolean enabled;

        public Trigger(int modifer) {
            this.modifier = modifer;
        }
    }

    private Map<Trigger, Manipulator> manips = new HashMap<Trigger, Manipulator>();
    private double width, height, aspect;

    public ManipulatorManager() {

    }

    private Vec3 normalizeScreenPos(int x, int y) {
        return new Vec3(Util.remap(x, 0, (double)width, -aspect, aspect), Util.remap(y, 0, (double)height, -1, 1), 0);
    }

    public void reshape(int width, int height) {
        this.width = width;
        this.height = height;
        aspect = (double)width/height;
    }

    public void setEnabled(MANIPULATOR manip, boolean state) {

    }

    public void add(int modifier, Manipulator manipulator) {
        manips.put(new Trigger(modifier), manipulator);
    }

    public void beginDrag(int x, int y, int modifier) {
        Manipulator manip = get(modifier);

        if(manip != null) {
            manip.beginDrag(normalizeScreenPos(x, y));
        }
    }
    
    public void drag(int x, int y, int modifier) {
        Manipulator manip = get(modifier);

        if(manip != null) {
            manip.drag(normalizeScreenPos(x, y));
        }
    }

    public void endDrag(int x, int y, int modifier) {
        Manipulator manip = get(modifier);

        if(manip != null) {
            manip.endDrag(normalizeScreenPos(x, y));
        }
    }
    
    public void move(int x, int y, int modifier) {
        for(Map.Entry entry : manips.entrySet()) {
            if(((Trigger)entry.getKey()).enabled == true) {
                Manipulator manip = (Manipulator)entry.getValue();
                manip.move(normalizeScreenPos(x, y));
            }
        }
    }

    private Manipulator get(int modifier) {
        for(Map.Entry entry : manips.entrySet()) {
            Trigger trigger = (Trigger) entry.getKey();
            if(trigger.enabled && trigger.modifier == modifier) {
                return (Manipulator)entry.getValue();
            }
        }
        return null;
    }

    /*
    public Matrix4x4 getTransform() {
        Matrix4x4 A = new Matrix4x4();
        A.setIdentity();

        for(Map.Entry entry : manips.entrySet()) {
            Manipulator manip = (Manipulator)entry.getValue();
            A.mulInplace(manip.getTransform());
        }
        
        return A;
    }
    */

    public void render(GL gl) {
        for(Map.Entry entry : manips.entrySet()) {
            if(((Trigger)entry.getKey()).enabled == true) {
                Manipulator manip = (Manipulator)entry.getValue();
                manip.render(gl);
            }
        }
    }

}
